#ifndef AUX_MESSAGE_H
#define AUX_MESSAGE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "config.h"
#include "aux_types.h"
#include "aux_errno.h"
#include "aux_buffer.h"
#include "aux_messagemanager.h"
#include "aux_thread.h"
#include "aux_socket.h"

typedef enum {
    CLIENT_STATE_UNKNOWN = -1,
    CLIENT_STATE_NOT_REGISTER = 0,
    CLIENT_STATE_REGISTER,
} ExIPCMessageClientConnectState;

typedef enum {
    CLIENT_SENDER_STATE_UNKNOWN = -1,
    CLIENT_SENDER_STATE_NOT_REGISTER = 0,
    CLIENT_SENDER_STATE_REGISTER,
} ExIPCMessageClientSenderRegisterState;

typedef enum {
    CLIENT_RECEIVER_STATE_UNKNOWN = 0,
    CLIENT_RECEIVER_STATE_NOT_REGISTER,
    CLIENT_RECEIVER_STATE_REGISTER,
} ExIPCMessageClientReceiverRegisterState;

typedef struct {
    char                szIpStr[IP_STR_LENGTH_MAX]; /* in case ipv6 */
    u16                 wPort;
    u32                 nRouterId;
    char                szRouterName[TERMINAL_NAME_LENGTH];
} TxIPCRouterInfo;

typedef enum {
    CLIENT_STATE_UNINITIALIZED = 0,
    CLIENT_STATE_WORKING,
    CLIENT_STATE_DYING,
    CLIENT_STATE_DEAD
} ExIPCClientState;


struct message_client_t{
    /*
     *                                   |-------------->delete
     *  Router----tcp/ip---> queue --->Handler---tcp/ip->Router
     *                       ^
     *  Thread-----send------|
     */
    TMessageManager  tMessageBufferQueue; /* store message to be handled */
    TMessageManager  tMessageSenderQueue; /* store msg to be sended to router */

    volatile int     nFlagDispatchProcessOn; /* thread handle message */
    pthread_t        tThreadMessageHandler;
    volatile ExIPCThreadState eDispatchProcessState;

    volatile int     nFlagSenderProcessOn; /* thread sending to router */
    pthread_t        tThreadMessageSender;
    volatile ExIPCThreadState eSenderProcessState;

    volatile int     nFlagListenerProcessOn; /* thread receiving from router */
    pthread_t        tThreadMessageListener;
    volatile ExIPCThreadState eListenerProcessState;

    TxIPCRouterInfo   tRouterInfo;

    u32               nClientId;
    char              szClient[TERMINAL_NAME_LENGTH]; /* name of this client */
    TxIPCSocketClient tSocketClient;

    ExIPCMessageClientConnectState eClientRegisterState;

    volatile ExIPCClientState  eClientActiveState;

    TxIPCBuffer       tRecvBuffer; /* only one buffer */
} ;
typedef struct message_client_t TxIPCMessageClient;

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////ROUTER/////////////////////////////////////////
struct message_router_t;

typedef enum {
    CLIENT_TYPE_UNKNOWN = 0,
    CLIENT_TYPE_SENDER,
    CLIENT_TYPE_LISTENER,
} ExIPCClientConnectionType;

//struct router_oneclient_t;

typedef struct {
    struct router_oneclient_t *ptClient;
    volatile int               nFlagThreadSendOrReceiveProcessOn;
    pthread_t                  tThreadSendOrReceive; /* send/receive thread */
    ExIPCThreadState           eThreadSendOrReceiveState;
    TxIPCSocket                tSocket;
    ExIPCClientConnectionType  eConnectionType;
    struct message_router_t   *ptRouter;
    TxIPCBuffer                tRecvBuffer;
} TxIPCRouter_OneClientConnection;

 typedef enum {
     ROUTER_CLIENT_STATE_UNINITIALIZED = 0,
     ROUTER_CLIENT_STATE_WORKING,
     ROUTER_CLIENT_ZOMBIE, /* client is going to die */
 } ExIPCRouterClientState;

 typedef struct router_oneclient_t{
    char                     szClientIpStr[IP_STR_LENGTH_MAX]; /* length for ipv6 */
    char                     szClientName[TERMINAL_NAME_LENGTH];
    u32                      nClientId;
    TMessageManager          tMessageSendManager;
    TQueue                   tConnectionPointerQueue; /* access with the queue lock */
    volatile ExIPCRouterClientState eClientState;
    struct message_router_t *ptRouter;
} TxIPCRouter_OneClient;

typedef enum {
    ROUTER_STATE_UNINITIALIZED = 0,
    ROUTER_STATE_INITIALIZED
} ExIPCRouterState;
typedef struct message_router_t{
    /*
     *                                   |-------------->delete
     *  Client----tcp/ip---> queue --->Handler---tcp/ip->Client
     *                       ^
     *  Thread-----send------|
     */
    TMessageManager  tMessageBufferQueue;    /* store message to be handled */
    TQueue           tClientPointerQueue; /* store clients TxIPCRouter_OneClient */

    volatile ExIPCThreadState eThreadMessageDispatchState;
    volatile int     nFlagDispatchProcessOn; /* thread handle message */
    pthread_t        tThreadMessageHandler;

    volatile ExIPCThreadState eThreadClientConnectListenerState;
    volatile int     nFlagClientConnectListenerProcessOn; /* listen on the port
                                             that client connecting to router */
    pthread_t        tThreadClientConnectListener;

    volatile ExIPCThreadState eThreadRouterInternalManagerState;
    volatile int     nFlagRouterInternalManagerProcessOn;
    pthread_t        tThreadRouterInternalManager;
    TMessageManager  tRouterInternalMessageQueue;

    u16              wPort;
    u32              nRouterId;
    char             szRouterName[TERMINAL_NAME_LENGTH];
    char             szIpStr[IP_STR_LENGTH_MAX]; /* in case ipv6 */

    TxIPCSocketServer tRouterServerSocketIntf;
    TxIPCSocket       tRouterSocket;
    ExIPCRouterState  eRouterState;
} TxIPCMessageRouter;

DLL_EXPORT EErrNo xIPC_Router_Init(TxIPCMessageRouter *ptRouter,
                                      char               *pszIp,
                                      u16                 wPort,
                                      char               *pszRouterName);

DLL_EXPORT EErrNo xIPC_Router_Deinit(TxIPCMessageRouter *ptRouter);

DLL_EXPORT EErrNo xIPC_Router_AddListener(TxIPCMessageRouter *ptRouter,
                                      TMessageListener    *ptListener);

DLL_EXPORT EErrNo xIPC_Router_DeleteListener(TxIPCMessageRouter *ptRouter,
                                          TMessageListener   *ptListener);

DLL_EXPORT EErrNo xIPC_Client_Init(TxIPCMessageClient *ptClient,
                                     char               *pszIp,
                                     u16                 wPort,
                                     char               *pszClientName);
DLL_EXPORT EErrNo xIPC_Client_Deinit(TxIPCMessageClient *ptClient);

DLL_EXPORT EErrNo xIPC_Client_Send(TxIPCMessageClient *ptClient, TMessage *ptMsg);

DLL_EXPORT EErrNo xIPC_Client_AddListener(TxIPCMessageClient *ptClient,
                                      TMessageListener    *ptListener);

DLL_EXPORT EErrNo xIPC_Client_DeleteListener(TxIPCMessageClient *ptClient,
                                          TMessageListener   *ptListener);

#define MESSAGE_PACKAGE_HEADER_START_FLAG 0xA5
#define MESSAGE_PACKAGE_HEADER_END_FLAG   0x5A
#ifdef __cplusplus
}
#endif
#endif
